package cgs_worksheet

import (
	"go.mongodb.org/mongo-driver/bson"
	"strconv"
	"strings"
)

type FilterType int
type FilterValue struct {
	QueryFlag string      // 查询符号
	Value     interface{} // 值
	FilterDataType
}

// 获取查询参数
func (filterValue FilterValue) GetFilterExpression(value string, dataType DataType) interface{} {
	v := filterValue.Value
	switch filterValue.FilterDataType {
	case String:
		return caseString(filterValue.QueryFlag, v.(string), value)
	case Boolean:
		return caseBool(filterValue.QueryFlag, v.(bool))
	case Number:
		return caseInt(filterValue.QueryFlag, value)
	case Any:
		return caseAny(filterValue.QueryFlag, value, v, dataType)
	}

	return nil
}

func caseAny(flag, value string, oldValue interface{}, dataType DataType) interface{} {
	switch DataTypeMap[dataType].FilterDataType {
	case String:
		return caseString(flag, oldValue.(string), value)
	case Number:
		return caseInt(flag, value)
	}

	return bson.M{}
}

func caseString(flag, oldValue, value string) interface{} {
	// 如果 queryFlag 为空，直接返回值
	if flag == "" {
		return strings.ReplaceAll(oldValue, "{Value}", value)
	}

	result := bson.D{
		{flag, strings.ReplaceAll(oldValue, "{Value}", value)},
	}

	return result
}

func caseInt(flag string, value string) interface{} {
	number, err := strconv.ParseFloat(value, 64)
	if err != nil {
		return bson.M{}
	}
	return bson.D{
		{flag, number},
	}
}

func caseBool(flag string, value bool) interface{} {
	return bson.D{
		{flag, value},
	}
}

const (
	DefaultFilterType FilterType = iota // (0,"默认"),
	Like                                //(1,"包含"),
	Eq                                  //(2,"是(等于)"),
	Start                               //(3,"开头为"),
	End                                 //4,"结尾为"),
	NotContain                          //(5,"不包含"),
	Ne                                  //(6,"不等于"),
	IsNull                              //(7,"为空"),
	HasValue                            //(8,"不为空"),
	RelationEq                          //(9,"不为空"),
	Between                             //(10,"在范围内"),
	NotBetween                          //(11,"不在范围内"),
	Gt                                  //(12,">"),
	Gte                                 //(13,">="),
	Lt                                  //(14,"<"),
	Lte                                 //(15,"<="),
	DateEnum                            //(16,"日期是"),
	NotDateEnum                         //(17,"日期不是"),
	Myself                              //(18,"我拥有的"),
	Unread                              //(19,"未读"),
	Sub                                 //(20,"下属"),
	RcEq                                //(21,"关联控件是"),
	RcNe                                //(22,"关联控件不是"),
	ArrEq                               //(23,"数组等于"),
	ArrNe                               //(24,"数组不等于");
)

type FilterDataType int

const (
	Any FilterDataType = iota
	Boolean
	Number
	String
	Date
)

func (f FilterType) GetFilterExpression(filter *FilterSortInput, wsInfo *WorksheetInfo) bson.D {
	s, ok := FilterTypeMap[f]

	if !ok {
		return nil
	}

	result := bson.D{}
	if filter.DataType == DATE {
		begin, end := filter.GetDateRange()

		switch f {
		case DateEnum: // 日期是
			result = append(result, bson.E{Key: filter.Field, Value: bson.M{"$gte": begin, "$lt": end}})
		case NotDateEnum: // 日期不是
			arr := bson.A{
				bson.D{{Key: filter.Field, Value: bson.M{"$lt": begin}}},
				bson.D{{Key: filter.Field, Value: bson.M{"$gte": end}}},
			}
			result = bson.D{{"$or", arr}}
		case Lt: // 早于
			result = append(result, bson.E{Key: filter.Field, Value: bson.M{"$lt": begin}})
		case Gt: // 晚于
			result = append(result, bson.E{Key: filter.Field, Value: bson.M{"$gte": end}})
		case Between: // 在范围内
			result = append(result, bson.E{Key: filter.Field, Value: bson.M{"$gte": begin, "$lte": end}})
		case NotBetween: // 不在范围内
			arr := bson.A{
				bson.D{{Key: filter.Field, Value: bson.M{"$lt": begin}}},
				bson.D{{Key: filter.Field, Value: bson.M{"$gt": end}}},
			}
			result = bson.D{{"$or", arr}}
		case IsNull: // 为空
			result = append(result, bson.E{Key: filter.Field, Value: bson.M{"$type": 10}})
		case HasValue: // 不为空
			result = append(result, bson.E{Key: filter.Field, Value: bson.M{"$type": 9}})
		}

	} else if filter.Values != nil && len(filter.Values) > 0 {
		// 多个值，或 的关系
		arr := bson.A{}
		for i := 0; i < len(filter.Values); i++ {
			value := filter.Values[i]
			ex := s.GetFilterExpression(value, filter.DataType)

			filter1 := bson.D{
				{filter.Field, ex},
			}
			arr = append(arr, filter1)
		}

		result = bson.D{
			{"$or", arr},
		}
	}

	return result
}

// 获取正则表达式
func getFilterTypeValue(s, value string) interface{} {

	if ok := strings.HasPrefix(s, "/"); ok {
		s = strings.TrimPrefix(s, "/")
		s = strings.ReplaceAll(s, "{Value}", value)
		return bson.M{
			"$regex": s,
		}
	}

	return strings.ReplaceAll(s, "{Value}", value)
}

var FilterTypeMap = map[FilterType]FilterValue{
	DefaultFilterType: {"", "{Value}", Any},
	Like:              {"$regex", ".*{Value}.*", String},
	Eq:                {"$eq", "{Value}", Any},
	Start:             {"$regex", "^{Value}", String},
	End:               {"$regex", "{Value}$", String},
	NotContain:        {"$regex", "^((?!{Value}).)*$", String},
	Ne:                {"$ne", "{Value}", String},
	IsNull:            {"$exists", false, Boolean},
	HasValue:          {"$exists", true, Boolean},
	RelationEq:        {"", "", Any},               // 不为空？
	Between:           {"", "", Any},               //"在范围内",
	NotBetween:        {"", "", Any},               // "不在范围内",
	Gt:                {"$gt", "{Value}", Number},  // ">",
	Gte:               {"$gte", "{Value}", Number}, // ">=",
	Lt:                {"$lt", "{Value}", Number},  // "<",
	Lte:               {"$lte", "{Value}", Number}, // "<=",
	DateEnum:          {"", "{Value}", String},     // "日期是",
	NotDateEnum:       {"", "", Any},               // "日期不是",
	Myself:            {"", "", Any},               // "我拥有的",
	Unread:            {"", "", Any},               // "未读",
	Sub:               {"", "", Any},               // "下属",
	RcEq:              {"", "", Any},               // "关联控件是",
	RcNe:              {"", "", Any},               // "关联控件不是",
	ArrEq:             {"", "", Any},               // "数组等于",
	ArrNe:             {"", "", Any},               // "数组不等于",
}
